package com.med.meddataintegrator.jwt.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.med.meddataintegrator.common.basic.exception.ServiceException;
import com.med.meddataintegrator.common.basic.response.StatusCode;
import com.med.meddataintegrator.jwt.pojo.dto.LoginUserParams;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 处理用户登录请求的过滤器
 *
 */

@Slf4j
public class JwtFilter extends AbstractAuthenticationProcessingFilter {

    /**
     * 无参构造函数
     * 通过父类构造器指定用户登录的访问地址
     */
    public JwtFilter() {
        /**
         * 使用 AntPathRequestMatcher 对象来匹配请求路径和请求方法。只对登录请求进行过滤，并调用 attemptAuthentication 方法进行认证。
         */
        super(new AntPathRequestMatcher("/user/login", "POST"));
    }



    /**
     * 此处用来实现自定义的登录认证逻辑
     * @param request
     * @param response
     * @return
     * @throws AuthenticationException
     * @throws IOException
     * @throws ServletException
     */

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {

        //从请求中拿到用户提交的数据信息 JSON反编译
        ObjectMapper mapper = new ObjectMapper();
        LoginUserParams loginUserParams = mapper.readValue(request.getInputStream(), LoginUserParams.class);

        //进行数据验证 是否为空
        if (loginUserParams == null || !StringUtils.hasText(loginUserParams.getUsername()) || !StringUtils.hasText(loginUserParams.getPassword())) {
            log.error("用户名或密码为空");
            throw new ServiceException(StatusCode.USERNAME_OR_PASSWORD_IS_NULL);
        }
        log.info("用户名:{} 登录",loginUserParams.getUsername());
        log.info("用户密码:{} 登录",loginUserParams.getPassword());

        //将拿到的数据 封装到Authentication的实现类之一中 这里是 UsernamePasswordAuthenticationToken
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
                new UsernamePasswordAuthenticationToken(loginUserParams.getUsername(), loginUserParams.getPassword());


        // 将封装好的类 放入到上下文对象中去进行认证处理  authenticate包含认证后的信息
        // 可以通过getPrincipal 获取实际用户对象 然后创建token返回前端
        // 此处认证逻辑 最后根据结果生成2个处理类
        // RestAuthenticationSuccessHandler 此处实现返回Token
        // RestAuthenticationFailureHandler 此处实现返回错误信息
        return getAuthenticationManager().authenticate(usernamePasswordAuthenticationToken);
    }
}